<?php
declare (strict_types=1);

namespace app\common\model;

use addons\Target\facade\Target;

class TradeOfflineOrder extends Base
{
    protected $type = [
        'pay_time' => 'timestamp',
        'receipt_time' => 'timestamp',
        'finish_time' => 'timestamp',
        'cancel_time' => 'timestamp',
        'appeal_time' => 'timestamp'
    ];

    protected function trade(): object
    {
        return $this->hasOne(TradeOffline::class, 'id', 'trade_id')
            ->field('id,sn,method');
    }

    protected function buyer(): object
    {
        return $this->hasOne(User::class, 'id', 'buyer_id')
            ->field('id,code,nickname,mobile,photo');
    }

    protected function seller(): object
    {
        return $this->hasOne(User::class, 'id', 'seller_id')
            ->field('id,code,nickname,mobile,photo,bank_name,bank_open_name,bank_number,bank_address,wechat_name,wechat_image,alipay_name,alipay_image,usdt_type,usdt_address,usdt_image');
    }

    protected function getAccountAttr($value): string
    {
        return get_pay_way($value);
    }

    protected function getMethodNameAttr($value, $data): string
    {
        return $data['method'] ? get_pay_way($data['method']) : '';
    }

    protected function getStatusNameAttr($value, $data): string
    {
        return getTradeOrderStatus($data['status']);
    }

    public static function _save($param, $options): array
    {
        parent::startTrans();
        try {
            if (empty($param['status'])) {
                throw new \Exception('请选择审核类型');
            }
            $info = parent::where(['id' => $param['id'], 'status' => 5])->find();
            if (empty($info)) {
                throw new \Exception('该交易订单不存在或已审核');
            }
            if ($param['status'] == 3) {
                $msg = '确认收款，交易订单ID【' . $param['id'] . '】';
                self::receiptOperation($info, $options);
            } else {
                $msg = '取消交易，交易订单ID【' . $param['id'] . '】';
                self::cancelOperation($info, $options);
            }
            Logs::adds($msg, $options['admin']->id, $options['admin']->admin_name);
            parent::commit();

            return ['code' => 1, 'msg' => '审核成功'];
        } catch (\Exception $e) {
            parent::rollback();

            return ['code' => -1, 'msg' => $e->getMessage()];
        }
    }

    public static function add($param, $user, $system): array
    {
        parent::startTrans();
        try {
            if (empty($system['trade_offline_open'])) {
                throw new \Exception('交易功能已关闭');
            }
            if ($system['trade_offline_min'] > $param['amount']) {
                throw new \Exception('最低交易数量：' . $system['trade_offline_min']);
            }
            if (!empty($system['trade_offline_bs'])) {
                if ($param['amount'] % $system['trade_offline_bs'] != 0) {
                    throw new \Exception('交易倍数：' . $system['trade_offline_bs']);
                }
            }
            if (md5($param['pay_password']) != $user->pay_password) {
                throw new \Exception('支付密码错误');
            }
            $info = TradeOffline::where(['id' => $param['id'], 'status' => 1])->lock(true)->find();
            if (empty($info)) {
                throw new \Exception('该交易不存在或已完成');
            }
            if ($info->uid == $user->id) {
                throw new \Exception('无法与自己进行交易');
            }
            if ($param['amount'] > $info->surplus_amount) {
                throw new \Exception('该交易剩余数量不足');
            }
            $account = $info->getData('account');
            if ($info->type_id == 1) {
                $buyer_id = $user->id;
                $seller_id = $info->uid;
                $cost_rate = 0;
                $msg = '交易成功，请去打款';
            } else {
                $method = explode(',', $info->method);
                if (in_array('bank', $method) && empty($user->bank_number)) {
                    throw new \Exception('请完善' . get_pay_way('bank') . '收款方式');
                }
                if (in_array('wechat', $method) && empty($user->wechat_image)) {
                    throw new \Exception('请完善' . get_pay_way('wechat') . '收款方式');
                }
                if (in_array('alipay', $method) && empty($user->alipay_image)) {
                    throw new \Exception('请完善' . get_pay_way('alipay') . '收款方式');
                }
                if (in_array('usdt', $method) && empty($user->usdt_address)) {
                    throw new \Exception('请完善' . get_pay_way('usdt') . '收款方式');
                }
                $real_amount = round($param['amount'] * (1 + $system['trade_offline_cost']), 2);
                if ($real_amount > $user->assets->$account) {
                    throw new \Exception(get_pay_way($account) . '账户余额不足');
                }
                $buyer_id = $info->uid;
                $seller_id = $user->id;
                $cost_rate = $system['trade_offline_cost'];
                $msg = '交易成功，请买家等待打款';
                Target::Account()->basics($seller_id, $account, $real_amount, '交易卖出', '-')
                    ->createNormal($buyer_id);
            }
            parent::create([
                'sn' => 'T' . date('YmdHis') . rand(100000, 999999) . $user->id,
                'trade_id' => $param['id'],
                'buyer_id' => $buyer_id,
                'seller_id' => $seller_id,
                'account' => $account,
                'amount' => $param['amount'],
                'price' => $info->price,
                'cost_rate' => $cost_rate,
                'real_amount' => round($param['amount'] * $info->price, 2),
                'expire_time' => round($system['trade_offline_pay_timeout'] * 60 + time())
            ]);
            $info->surplus_amount -= $param['amount'];
            if ($info->surplus_amount <= 0) {
                $info->status = 2;
                $info->finish_time = time();
            }
            $info->save();
            parent::commit();

            return ['code' => 1, 'msg' => $msg];
        } catch (\Exception $e) {
            parent::rollback();

            return ['code' => -1, 'msg' => $e->getMessage()];
        }
    }

    public static function confirmPayment($param, $user, $system): array
    {
        parent::startTrans();
        try {
            $info = parent::where(['id' => $param['id'], 'buyer_id' => $user->id, 'status' => 1])
                ->where('expire_time', '>', time())->find();
            if (empty($info)) {
                throw new \Exception('交易订单不存在或是已过期');
            }
            $info->method = $param['method'];
            $info->images = $param['images'];
            $info->status = 2;
            $info->pay_time = time();
            $info->auto_receipt_time = round($system['trade_offline_auto_receipt_time'] * 60 + time());
            $info->save();
            parent::commit();

            return ['code' => 1, 'msg' => '打款成功，请等待卖家确认收款'];
        } catch (\Exception $e) {
            parent::rollback();

            return ['code' => -1, 'msg' => $e->getMessage()];
        }
    }

    public static function confirmReceipt($param, $user): array
    {
        parent::startTrans();
        try {
            $info = parent::where(['id' => $param['id'], 'seller_id' => $user->id, 'status' => 2])
                ->where('auto_receipt_time', '>', time())->find();
            if (empty($info)) {
                throw new \Exception('交易订单不存在或是已完成');
            }
            $res = self::receiptOperation($info);
            if ($res !== true) {
                throw new \Exception($res);
            }
            parent::commit();

            return ['code' => 1, 'msg' => '确认收款成功'];
        } catch (\Exception $e) {
            parent::rollback();

            return ['code' => -1, 'msg' => $e->getMessage()];
        }
    }

    public static function appeal($param, $user): array
    {
        parent::startTrans();
        try {
            $info = parent::where(['id' => $param['id'], 'seller_id' => $user->id, 'status' => 2])
                ->where('auto_receipt_time', '>', time())->find();
            if (empty($info)) {
                throw new \Exception('交易订单不存在或是已完成');
            }
            $info->content = $param['content'];
            $info->appeal_img = $param['appeal_img'];
            $info->status = 5;
            $info->appeal_time = time();
            $info->save();
            parent::commit();

            return ['code' => 1, 'msg' => '申诉成功，请等待审核'];
        } catch (\Exception $e) {
            parent::rollback();

            return ['code' => -1, 'msg' => $e->getMessage()];
        }
    }

    public static function receiptOperation($info, $options = []): bool|string
    {
        try {
            $info->status = 3;
            $info->receipt_time = time();
            $info->finish_time = time();
            if ($options) {
                $info->admin_id = $options['admin']->id;
                $info->admin_name = $options['admin']->admin_name;
            }
            $info->save();
            Target::Account()->basics($info->buyer_id, $info->getData('account'), $info->amount, '交易买入', '+')
                ->createNormal();

            return true;
        } catch (\Exception $e) {

            return $e->getMessage();
        }
    }

    public static function cancelOperation($info, $options = []): bool|string
    {
        try {
            $info->status = 4;
            $info->cancel_time = time();
            if ($options) {
                $info->admin_id = $options['admin']->id;
                $info->admin_name = $options['admin']->admin_name;
            }
            $info->save();
            $trade = TradeOffline::where(['id' => $info->trade_id])->find();
            $trade->status = 1;
            $trade->surplus_amount += $info->amount;
            $trade->save();
            if ($trade->type_id == 2) {
                $real_amount = round($info->amount * (1 + $info->cost_rate), 2);
                Target::Account()->basics($info->seller_id, $info->getData('account'), $real_amount, '交易取消', '+')
                    ->createNormal();
            }

            return true;
        } catch (\Exception $e) {

            return $e->getMessage();
        }
    }

    /**
     * 交易打款超时自动取消
     * 定时
     */
    public static function paymentTimeout(): array
    {
        parent::startTrans();
        try {
            parent::where(['status' => 1])->where('expire_time', '<=', time())->select()->each(function ($item) {
                self::cancelOperation($item);
            });
            parent::commit();

            return ['code' => 1, 'msg' => '执行成功'];
        } catch (\Exception $e) {
            parent::rollback();
            Logs::write('logs/trade-paymentTimeout.log', $e->getMessage());

            return ['code' => -1, 'msg' => $e->getMessage()];
        }
    }

    /**
     * 交易自动确认收款
     * 定时
     */
    public static function autoReceipt(): array
    {
        parent::startTrans();
        try {
            parent::where(['status' => 2])->where('auto_receipt_time', '<=', time())->select()->each(function ($item) {
                self::receiptOperation($item);
            });
            parent::commit();

            return ['code' => 1, 'msg' => '执行成功'];
        } catch (\Exception $e) {
            parent::rollback();
            Logs::write('logs/trade-autoReceipt.log', $e->getMessage());

            return ['code' => -1, 'msg' => $e->getMessage()];
        }
    }
}